#include <iostream>
#include <fstream>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>

#define PORT 5001
#define BUFFER_SIZE 4096

void handle_client(int client_socket) {
    char buffer[BUFFER_SIZE];

    // 接收文件名和大小
    recv(client_socket, buffer, BUFFER_SIZE, 0);
    std::string file_info(buffer);
    size_t separator = file_info.find(',');
    std::string filename = file_info.substr(0, separator);
    long filesize = std::stol(file_info.substr(separator + 1));

    std::ofstream outfile(filename, std::ios::binary);
    if (!outfile.is_open()) {
        std::cerr << "无法打开文件进行写入\n";
        close(client_socket);
        return;
    }

    long bytes_received = 0;
    while (bytes_received < filesize) {
        ssize_t len = recv(client_socket, buffer, BUFFER_SIZE, 0);
        if (len <= 0) break;
        outfile.write(buffer, len);
        bytes_received += len;
        std::cout << "接收中... " << (100.0 * bytes_received / filesize) << "%\n";
    }

    std::cout << "文件接收完成: " << filename << "\n";
    outfile.close();
    close(client_socket);
}

int main() {
    int server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1) {
        std::cerr << "无法创建socket\n";
        return -1;
    }

    sockaddr_in server_addr = {};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(server_socket, (sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        std::cerr << "无法绑定socket\n";
        return -1;
    }

    if (listen(server_socket, 5) == -1) {
        std::cerr << "监听失败\n";
        return -1;
    }

    std::cout << "服务器启动，在端口 " << PORT << " 监听...\n";

    while (true) {
        int client_socket = accept(server_socket, nullptr, nullptr);
        if (client_socket == -1) {
            std::cerr << "接受连接失败\n";
            continue;
        }
        handle_client(client_socket);
    }

    close(server_socket);
    return 0;
}
